package com.roamer.school.web.aspect;

import com.roamer.school.common.exception.suppert.UserNotLoginException;
import com.roamer.school.repository.entity.sys.SysUser;
import com.roamer.school.shiro.util.ShiroUtils;
import com.roamer.school.web.annotation.LoginedAuth;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import java.lang.reflect.Method;

/**
 * 登陆用户 参数解析器
 * <p>
 * 自动注入当前登陆用户
 * </p>
 *
 * @author roamer
 * @version V1.0
 * @date 2019/1/28 10:57
 */
public class LoginUserArgumentResolver implements HandlerMethodArgumentResolver {

    /**
     * 用于判断当前参数是否需要转换类型
     *
     * @param parameter 源参数
     *
     * @return {@code true} 类/方法标注 {@link LoginedAuth} ，并且参数类型为 {@link SysUser}
     */
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        final Method method = parameter.getMethod();
        if (method != null) {
            final Class<?> clazz = method.getDeclaringClass();
            boolean isHasLoginAuthAnn = clazz.isAnnotationPresent(LoginedAuth.class) || method
                    .isAnnotationPresent(LoginedAuth.class);
            boolean isHasLoginUserParameter = parameter.getParameterType().isAssignableFrom(SysUser.class);
            return isHasLoginAuthAnn && isHasLoginUserParameter;
        }
        return false;
    }

    /**
     * 参数转换
     *
     * @param parameter     源参数
     * @param mavContainer
     * @param webRequest
     * @param binderFactory
     *
     * @return {User}
     *
     * @throws UserNotLoginException 当用户未登陆时，则抛出异常
     */
    @Override
    public Object resolveArgument(
            MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
            WebDataBinderFactory binderFactory) throws UserNotLoginException {
        return ShiroUtils.getCurrentUser().orElseThrow(UserNotLoginException::new);
    }
}
